package com.blz.flare.elasticsearch;

import static org.elasticsearch.common.xcontent.XContentFactory.*;
import static org.elasticsearch.node.NodeBuilder.*;

import com.blz.flare.crawler.PostException;
import com.sun.jndi.toolkit.url.UrlUtil;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Elastic search implementation of the {@link com.blz.flare.solr.SolrUpdaterTool}.
 * TODO: introduce interface?
 *
 * {@see org.elasticsearch}
 */
public class ElasticSearchUpdaterTool {

    private static final Logger logger = LoggerFactory.getLogger(ElasticSearchUpdaterTool.class);

    private Map<String, Integer> indexHostInformation = new HashMap<String, Integer>();
    private boolean sniffCluster;

    /**
     * Get an instance of the {@link Client}.
     * @return the client
     */
    private Client getClient() {

        TransportClient client;

        // if sniff cluster is set to true, set the client.transport.sniff setting to true
        if (sniffCluster) {
            client = new TransportClient(ImmutableSettings.settingsBuilder().put("client.transport.sniff", true));
        } else {
            client = new TransportClient();
        }

        // add all the clients
        for (Map.Entry<String, Integer> i : indexHostInformation.entrySet()) {
            client.addTransportAddress(new InetSocketTransportAddress(i.getKey().toString(), i.getValue().intValue()));
        }

        return client;
    }

    /**
     * Update elastic search indexes.
     * @param url the url
     * @param title the title
     * @param text the text
     * @param indexFields the fields to index
     * @throws com.blz.flare.crawler.PostException on error
     */
    public void updateIndexes(URL url, String title, String text, Map<String, String> indexFields)
            throws PostException {

        logger.debug("publishing indexes for url: "+url);
        Client client = getClient();

        // TODO: change index name (pages) and type (page)
        try {

            // create the object for indexing
            XContentBuilder builder = jsonBuilder().startObject()
                    .startObject()
                    .field("title", title)
                    .field("text", text);

            // add all the extra fields
            for (Map.Entry<String, String> field : indexFields.entrySet()) {
                builder.field(field.getKey(), field.getValue());
            }
            builder.endObject();

            // prepare the index and execute
            client.prepareIndex("pages", "page", url.toString())
                    .setSource(builder)
                    .execute()
                    .actionGet();
        } catch(IOException ex) {
            throw new PostException("unable to post to elasticsearch", ex);
        }
        
        // close the client
        client.close();
    }

    /**
     * @param indexHostInformation the host information to set
     */
    public void setIndexHostInformation(Map<String, Integer> indexHostInformation) {
        this.indexHostInformation = indexHostInformation;
    }

    /**
     * @param sniffCluster true if you want to allow the client to sniff the rest
     * of the cluster  and add those to the machine to use.
     */
    public void setSniffCluster(boolean sniffCluster) {
        this.sniffCluster = sniffCluster;
    }
}
